package cn.nuofankj.myblog.service.impl;

import cn.nuofankj.myblog.constant.ArticleStatusEnum;
import cn.nuofankj.myblog.constant.PagesTypeEnum;
import cn.nuofankj.myblog.constant.TagStatusEnum;
import cn.nuofankj.myblog.dto.impl.*;
import cn.nuofankj.myblog.entity.*;
import cn.nuofankj.myblog.repository.*;
import cn.nuofankj.myblog.service.ApiService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * @author xifanxiaxue
 * @date 2020-12-20
 * @desc
 */
@Service
@Configuration
@Slf4j
public class ApiServiceImpl implements ApiService {

    @Autowired
    private BlogConfigRepository blogConfigRepository;
    @Autowired
    private CategoryRepository categoryRepository;
    @Autowired
    private TagRepository tagRepository;
    @Autowired
    private ArticleRepository articleRepository;
    @Autowired
    private PagesRepository pagesRepository;
    @Autowired
    private CommentsRepository commentsRepository;
    @Autowired
    private ArticleTagMapperRepository articleTagMapperRepository;
    @Autowired
    private FriendsRepository friendsRepository;
    @Autowired
    private FriendsTypeRepository friendsTypeRepository;

    @Override
    public BlogConfigDto blogInfo() {

        List<BlogConfig> all = blogConfigRepository.findAll();
        if(all.size() == 0) {
            log.error("BlogConfig为空，要报错啦！！！");
            return null;
        }
        // TODO 暫時取第一個
        BlogConfig blogConfig = all.get(0);
        long categoryCount = categoryRepository.count();
        long tagCount = tagRepository.count();
        long articleCount = articleRepository.count();
        BlogConfigDto blogConfigDto = BlogConfigDto.toDTO(blogConfig, categoryCount, tagCount, articleCount);
        return blogConfigDto;
    }

    @Override
    public AboutDto about() {
        List<BlogConfig> configs = blogConfigRepository.findAll();
        if(configs.size() == 0) {
            log.error("BlogConfig为空，要报错啦！！！");
            return null;
        }
        BlogConfig blogConfig = configs.get(0);
        Map<String, String> qrcode = new HashMap<>();
        qrcode.put("wxpayQrcode", blogConfig.getWxpayQrcode());
        qrcode.put("alipayQrcode", blogConfig.getAlipayQrcode());
        Pages page = pagesRepository.findPagesByType(PagesTypeEnum.ABOUT.getStatusMsg());
        if (page == null) {
            return AboutDto.valueOf(qrcode, null);
        } else {
            String html = page.getHtml();
            return AboutDto.valueOf(qrcode, html);
        }
    }

    @Override
    public CommentsDto comments(String articleId) {
        Article articleTmp = articleRepository.findArticleById(articleId);
        String title = null;
        if(articleTmp != null) {
            title = articleTmp.getTitle();
        }
        // TODO 此处暂定封顶100
        Pageable pageable = PageRequest.of(0, 100, Sort.Direction.DESC, "id");
        List<Comments> commentsList = commentsRepository.findAllByParentIdAndArticleId(0, articleId, pageable);
        List<CommentDto> list = new ArrayList<>();
        for(Comments comments : commentsList) {
            CommentDto commentDto = CommentDto.toDto(comments, title);
            List<Comments> allByParentId = commentsRepository.findAllByParentId(comments.getId(), pageable);
            List<CommentDto> listTmp = new ArrayList<>();
            for(Comments c : allByParentId) {
                listTmp.add(CommentDto.toDto(c, title));
            }
            commentDto.setChildren(listTmp);
            list.add(commentDto);
        }
        CommentsDto commentsDto = CommentsDto.valueOf(list, list.size());
        return commentsDto;
    }

    @Override
    public ArticleInfoDetailDto articles(String by, String categoryId, String tagId, int page, int pageSize) {

        List<Article> articles = new ArrayList<>();
        Pageable pageable;
        switch (by) {
            case "category":
                pageable = PageRequest.of(page, pageSize, Sort.Direction.DESC, "publishTime");
                articles = articleRepository.findAllByStatusAndCategoryId(ArticleStatusEnum.NORMAL.getStatus(), categoryId, pageable );
                break;

            case "tag":
                pageable = PageRequest.of(page, pageSize, Sort.Direction.DESC, "createTime");
                List<ArticleTagMapper> allByTagId = articleTagMapperRepository.findAllByTagId(tagId, pageable);
                for(ArticleTagMapper articleTagMapper : allByTagId) {
                    Article articleById = articleRepository.findArticleByIdAndStatus(articleTagMapper.getArticleId(), ArticleStatusEnum.NORMAL.getStatus());
                    if(articleById != null) {
                        articles.add(articleById);
                    }
                }
                break;

            default:
                pageable = PageRequest.of(page, pageSize, Sort.Direction.DESC, "publishTime");
                articles = articleRepository.findAllByStatusAndIdNotContains(ArticleStatusEnum.NORMAL.getStatus(), "-1", pageable);
                ;
        }

        List<ArticleMsgDetailDto> articleDetailDtos = new ArrayList<>();
        for(Article article : articles) {
            Category category = categoryRepository.findCategoryById(article.getCategoryId());

            List<Tag> tags = new ArrayList<>();

            List<ArticleTagMapper> articleTagMappers = articleTagMapperRepository.findAllByArticleId(article.getId());
            for(ArticleTagMapper articleTagMapper : articleTagMappers) {
                Tag tag = tagRepository.findTagById(articleTagMapper.getTagId());
                tags.add(tag);
            }
            ArticleMsgDetailDto articleDetailDto = ArticleMsgDetailDto.valueOf(article, category, tags, null, null);
            articleDetailDtos.add(articleDetailDto);
        }
        ArticleInfoDetailDto articlesDto = ArticleInfoDetailDto.valueOf(page, pageSize, articles.size(), articleDetailDtos);
        return articlesDto;
    }

    @Override
    public ArticleDetailDto article(String id) {

        List<BlogConfig> configs = blogConfigRepository.findAll();
        if(configs.size() == 0) {
            log.error("BlogConfig为空，要报错啦！！！");
            return null;
        }
        // TODO 暫時取第一個
        BlogConfig blogConfig = configs.get(0);
        Map<String, String> qrcode = new HashMap<>();
        qrcode.put("wxpayQrcode", blogConfig.getWxpayQrcode());
        qrcode.put("alipayQrcode", blogConfig.getAlipayQrcode());

        Article article = articleRepository.findArticleById(id);

        Category category = categoryRepository.findCategoryById(article.getCategoryId());

        List<ArticleTagMapper> articleTagMappers = articleTagMapperRepository.findAllByArticleId(article.getId());

        List<Tag> tags = new ArrayList<>();

        for(ArticleTagMapper articleTagMapper : articleTagMappers) {
            Tag tag = tagRepository.findTagById(articleTagMapper.getTagId());
            tags.add(tag);
        }

        Map<String, ArticleDescDto> pn = new HashMap<>();
        Pageable pageable = PageRequest.of(0, 1, Sort.Direction.DESC, "aid");
        List<Article> byAidLessThan = articleRepository.findByAidLessThanAndStatus(article.getAid(), ArticleStatusEnum.NORMAL.getStatus(), pageable);
        List<Article> byAidGreaterThan = articleRepository.findByAidGreaterThanAndStatus(article.getAid(), ArticleStatusEnum.NORMAL.getStatus(), pageable);
        if(byAidLessThan.size() > 0) {
            ArticleDescDto articleDescDto = ArticleDescDto.toDTO(byAidLessThan.get(0));
            pn.put("pre", articleDescDto);
        }
        if(byAidGreaterThan.size() > 0) {
            ArticleDescDto articleDescDto = ArticleDescDto.toDTO(byAidGreaterThan.get(0));
            pn.put("next", articleDescDto);
        }

        ArticleDetailDto articleDetailDto = ArticleDetailDto.valueOf(article, category, tags, qrcode, pn);

        article.setPageview(article.getPageview() + 1);
        articleRepository.save(article);

        return articleDetailDto;
    }

    @Override
    public void addComment(String ip,String articleId, long parentId, String name, int replyId, String content, String sourceContent, String ticket, String randstr, String email) {

        Comments comments = new Comments();
        comments.setArticleId(articleId);
        comments.setParentId(parentId);
        comments.setName(name);
        comments.setReplyId(replyId);
        comments.setContent(content);
        comments.setSourceContent(sourceContent);
        comments.setEmail(email);
        comments.setCreateTime(new Date().getTime());
        comments.setIp(ip);
        Optional<Comments> commentsOptiona = commentsRepository.findById((long)replyId);
        if(commentsOptiona == null) {
            Comments commentsTmp = commentsOptiona.get();
            comments.setParentId(commentsTmp.getId());
        }
        commentsRepository.save(comments);
    }

    @Override
    public CategorysDto categorys() {
        List<Category> categories = categoryRepository.findAll();
        CategorysDto categorysDto = CategorysDto.valueOf(categories.size(), categories);
        return categorysDto;
    }

    @Override
    public TagsDetailDto tags() {
        List<Tag> tags = tagRepository.findAllByStatus(TagStatusEnum.NORMAL.getStatus());
        TagsDetailDto tagsDetailDto = TagsDetailDto.valueOf(tags.size(), tags);
        return tagsDetailDto;
    }

    @Override
    public FriendsTypeDto[] friends() {
        List<FriendsType> friendsTypes = friendsTypeRepository.findAll();
        FriendsTypeDto[] friendsTypeDtos = new FriendsTypeDto[friendsTypes.size()];
        int size = 0;
        for(FriendsType friendsType : friendsTypes) {
            List<Friends> friends = friendsRepository.findAllByTypeId(friendsType.getId());
            FriendsTypeDto friendsTypeDto = FriendsTypeDto.toDTO(friendsType, friends);
            friendsTypeDtos[size] = friendsTypeDto;
            size ++;
        }
        return friendsTypeDtos;
    }

    @Override
    public SearchDto search(String searchValue, int page, int pageSize) {
        Pageable pageable = PageRequest.of(page, pageSize, Sort.Direction.DESC, "aid");
        List<Article> articles = articleRepository.findAllByTitleContainingAndStatus(searchValue, ArticleStatusEnum.NORMAL.getStatus(), pageable);
        List<ArticleDetailDto> articleDetailDtos = new ArrayList<>();
        for(Article article : articles) {
            Category category = categoryRepository.findCategoryById(article.getCategoryId());

            List<Tag> tags = new ArrayList<>();

            List<ArticleTagMapper> articleTagMappers = articleTagMapperRepository.findAllByArticleId(article.getId());
            for(ArticleTagMapper articleTagMapper : articleTagMappers) {
                Tag tag = tagRepository.findTagById(articleTagMapper.getTagId());
                tags.add(tag);
            }
            ArticleDetailDto articleDetailDto = ArticleDetailDto.valueOf(article, category, tags, null, null);
            articleDetailDtos.add(articleDetailDto);
        }
        ArticlesDto articlesDto = ArticlesDto.valueOf(page, pageSize, articles.size(), articleDetailDtos);
        SearchDto searchDto = SearchDto.valueOf(page, pageSize, articleDetailDtos.size(), articleDetailDtos);
        return searchDto;
    }

    @Override
    public ArchivesDetailDto archives(int page, int pageSize) {
        Map<String, Map<String, List<ArticleDetailDto>>> yearsMap = new TreeMap<>(new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return -o1.compareTo(o2);
            }
        });
        Pageable pageable = PageRequest.of(page, pageSize, Sort.Direction.DESC, "publishTime");
        List<Article> articles = articleRepository.findAllByStatusAndIdNotContains(ArticleStatusEnum.NORMAL.getStatus(), "-1", pageable);
        for(Article article : articles) {
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(new Date(article.getPublishTime() * 1000));
            String year = calendar.get(Calendar.YEAR) + "年";
            String month = calendar.get(Calendar.MONTH) + 1  + "月";
            Map<String, List<ArticleDetailDto>> monthsMap = yearsMap.get(year);
            if(monthsMap == null) {
                monthsMap = new TreeMap<>(new Comparator<String>() {
                    @Override
                    public int compare(String o1, String o2) {
                        int m1 = Integer.parseInt(o1.replace("月",""));
                        int m2 = Integer.parseInt(o2.replace("月",""));
                        return m2 - m1;
                    }
                });
                yearsMap.put(year, monthsMap);
            }
            List<ArticleDetailDto> articleDetailDtos = monthsMap.get(month);
            if(articleDetailDtos == null) {
                articleDetailDtos = new ArrayList<>();
                monthsMap.put(month, articleDetailDtos);
            }

            Category category = categoryRepository.findCategoryById(article.getCategoryId());
            List<Tag> tags = new ArrayList<>();
            List<ArticleTagMapper> articleTagMappers = articleTagMapperRepository.findAllByArticleId(article.getId());
            for(ArticleTagMapper articleTagMapper : articleTagMappers) {
                Tag tag = tagRepository.findTagById(articleTagMapper.getTagId());
                tags.add(tag);
            }
            ArticleDetailDto articleDetailDto = ArticleDetailDto.valueOf(article, category, tags, null, null);
            articleDetailDtos.add(articleDetailDto);
        }
        int count = articleRepository.countArticlesByStatusAndIdNotContaining(ArticleStatusEnum.NORMAL.getStatus(), "-1");
        return ArchivesDetailDto.valueOf(page, pageSize, count, yearsMap);
    }

    @Override
    public ResumeDto resume() {
        Pages page = pagesRepository.findPagesByType(PagesTypeEnum.RESUME.getStatusMsg());
        return ResumeDto.toDto(page);
    }
}
